// ===============================
// digit_monitor.v
// - 输入：clk、rst_n、i2s_bclk、b16_data/b16_vld
// - 功能：20ms绝对值平均（I2S域），CDC回clk域，驱动digitshow
// - 说明：T0_COUNT 默认 1_000_000（≈20ms@50MHz）
// ===============================
module digit_monitor #(
    parameter [19:0] T0_COUNT = 20'd1_000_000  // 定时计数（-1 在比较里体现）
)(
    input  wire        clk,        // 50MHz
    input  wire        rst_n,
    input  wire        i2s_bclk,   // I2S bit clock
    input  wire [15:0] b16_data,   // I2S域数据
    input  wire        b16_vld,    // I2S域数据有效
    output wire [7:0]  digit_seg,
    output wire [3:0]  digit_dig
);

    // ---------------------------------------------
    // clk 域：20ms 定时（保持 1_000_000-1）
    // 用 toggle 表示事件以防跨域丢脉冲
    // ---------------------------------------------
    reg [19:0] t0_cnt;
    reg        t0_toggle_clk;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            t0_cnt        <= 20'd0;
            t0_toggle_clk <= 1'b0;
        end else if (t0_cnt == T0_COUNT - 1) begin // ≈20ms@50MHz
            t0_cnt        <= 20'd0;
            t0_toggle_clk <= ~t0_toggle_clk;
        end else begin
            t0_cnt <= t0_cnt + 1'b1;
        end
    end

    // ---------------------------------------------
    // clk → i2s_bclk：同步 toggle 并做边沿检测
    // 得到 i2s_bclk 域 1clk 脉冲
    // ---------------------------------------------
    reg [2:0] t0_sync_bclk;
    always @(posedge i2s_bclk or negedge rst_n) begin
        if (!rst_n) t0_sync_bclk <= 3'b000;
        else        t0_sync_bclk <= {t0_sync_bclk[1:0], t0_toggle_clk};
    end
    wire t0_pulse_bclk = t0_sync_bclk[2] ^ t0_sync_bclk[1];

    // ---------------------------------------------
    // I2S_BCLK 域：绝对值累加 + 20ms 窗口结算
    // 结算时：有样本则更新平均；无样本保持上一帧
    // 用 avg_toggle_bclk 告知 clk 域“新值就绪”
    // ---------------------------------------------
    reg [47:0] sum_accum;
    reg [19:0] sample_cnt;
    wire [15:0] abs_sample = b16_data[15] ? (~b16_data + 16'd1) : b16_data;

    reg [15:0] avg_buf_bclk;
    reg        avg_toggle_bclk;

    always @(posedge i2s_bclk or negedge rst_n) begin
        if (!rst_n) begin
            sum_accum       <= 48'd0;
            sample_cnt      <= 20'd0;
            avg_buf_bclk    <= 16'd0;
            avg_toggle_bclk <= 1'b0;
        end else if (t0_pulse_bclk) begin
            if (sample_cnt != 0) begin
                avg_buf_bclk <= sum_accum / sample_cnt; // 若担心时序，可换 >>K 或顺序除法IP
            end
            avg_toggle_bclk <= ~avg_toggle_bclk; // 新平均值就绪
            sum_accum  <= 48'd0;
            sample_cnt <= 20'd0;
        end else if (b16_vld) begin
            sum_accum  <= sum_accum + abs_sample;
            sample_cnt <= sample_cnt + 1'b1;
        end
    end

    // ---------------------------------------------
    // i2s_bclk → clk：同步“就绪”翻转位并边沿检测
    // 总线双级同步 + 延迟一拍原子锁存，杜绝位撕裂
    // ---------------------------------------------
    reg [2:0] avg_tgl_sync_clk;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) avg_tgl_sync_clk <= 3'b000;
        else        avg_tgl_sync_clk <= {avg_tgl_sync_clk[1:0], avg_toggle_bclk};
    end
    wire new_avg_edge_clk = avg_tgl_sync_clk[2] ^ avg_tgl_sync_clk[1];

    reg [15:0] avg_bus_sync1_clk, avg_bus_sync2_clk;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            avg_bus_sync1_clk <= 16'd0;
            avg_bus_sync2_clk <= 16'd0;
        end else begin
            avg_bus_sync1_clk <= avg_buf_bclk;
            avg_bus_sync2_clk <= avg_bus_sync1_clk;
        end
    end

    reg        capture_pending;
    reg [15:0] avg_data_clk;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            capture_pending <= 1'b0;
            avg_data_clk    <= 16'd0;
        end else if (new_avg_edge_clk) begin
            capture_pending <= 1'b1;               // 下一拍取数
        end else if (capture_pending) begin
            avg_data_clk    <= avg_bus_sync2_clk;  // 原子锁存
            capture_pending <= 1'b0;
        end
    end

    // ---------------------------------------------
    // 数码管显示（clk 域稳定数据）
    // ---------------------------------------------
    wire [15:0] avg16 = avg_data_clk;
    wire [3:0]  dig3 = avg16[15:12];
    wire [3:0]  dig2 = avg16[11:8];
    wire [3:0]  dig1 = avg16[7:4];
    wire [3:0]  dig0 = avg16[3:0];

    digitshow u_digit (
        .clk       (clk),
        .rst_n     (rst_n),
        .data_in_1 (dig0),
        .data_in_2 (dig1),
        .data_in_3 (dig2),
        .data_in_4 (dig3),
        .data_vld  (4'b1111),      // 若 digitshow 有外部锁存，可用 new_avg_edge_clk 代替/参与
        .seg       (digit_seg),
        .dig       (digit_dig)
    );

endmodule
